﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using smarx.HostedWebCore;
using System.Collections.Specialized;
using System.IO;
using Microsoft.Cis.E2E.COMMON;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using InstanceManagerServer;

namespace HWCWorker_Worker
{
    public class WorkerRole : RoleEntryPoint
    {
        #region Added for backup
        private Thread _setFullBackupThread;
        private ManualResetEvent _fullBackuprecycleEvent;
        private Thread _setIncrementalBackupThread;
        private ManualResetEvent _incrementalBackuprecycleEvent;
        private bool IsFullBackupRunning = false;
        private bool IsIncrementalBackupRunning = false;
        private DateTime? FullBackupDate;
        #endregion
        private const string ElectionServiceEndpoint = "MasterElectionService";
        private const int QueryIntervalInSeconds = 10;
        private const int RetryLimit = 6;
        private static string VerTag = "V0:";
        private string instanceId = string.Empty;
        private LogClient _logger;
        private MasterElectionService _masterElector;
        private ManualResetEvent _recycleEvent;
        private ManualResetEvent _masterRecycleEvent;
        private Thread _masterWatchdogThread;
        private RoleInstance ThisInstance { get; set; }
        private PeerActive _pingAlive;
        private static bool IsFailover = false;

        private HWCServer hwcServer;
        private DiagnosticMonitor diagnosticMonitor;

        #region Added By Sudhir
        StringWriter output = new StringWriter();
        StringWriter error = new StringWriter();
        Timer timer = null;
        #endregion

        public override void Run()
        {
            //Thread.Sleep(Timeout.Infinite);
            Trace.WriteLine("HWCWorker_Worker entry point called", "Information");

            //  for (; ; )
            //   {

            bool useHWC = false;

            string result = string.Empty;
            // This is a sample worker implementation. Replace with your logic.
            Trace.WriteLine("WorkerRole entry point called", "Information");

            string time = string.Empty;

            //Get the duration from config file
            try
            {
                try
                {
                    time = RoleEnvironment.GetConfigurationSettingValue("Duration");
                }
                catch (Exception ex)
                {
                    //Execute once if the duration node is not present
                    Execute(null);
                    return;
                }

                time = time.Trim();

                //If no value exists for Duration
                if (time == null || time.Length == 0)
                {
                    //Execute once if duration node value empty
                    Execute(null);
                }
                else
                {
                    string[] splitTime = time.Split(':');

                    //Set the timer
                    TimeSpan ts = new TimeSpan(Convert.ToInt32(splitTime[0]), Convert.ToInt32(splitTime[1]), Convert.ToInt32(splitTime[2]));
                    System.Threading.TimerCallback cb = new TimerCallback(Execute);
                    timer = new System.Threading.Timer(cb, null, new TimeSpan(0), ts);
                }

            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, "Error");
            }


            try
            {
                useHWC = Convert.ToBoolean(RoleEnvironment.GetConfigurationSettingValue("UseHWC"));

                if (useHWC == false)
                {
                    while (true)
                    {
                        Thread.Sleep(10000);
                        Trace.WriteLine("Working", "Information");
                    }
                }
            }
            catch
            {
                while (true)
                {
                    Thread.Sleep(10000);
                    Trace.WriteLine("Working", "Information");
                }
            }

            try
            {
                instanceId = "Worker Role instance:: " + ThisInstance.Id;
                Logger("In start method: {0}", instanceId);
                Logger("UpgradeDomain: {0}", ThisInstance.UpdateDomain);
                //Instantiates and starts the instance manager server
                InstanceMgrTcpServer server = new InstanceMgrTcpServer(
                 RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["InstanceManagerEndpontIn"].IPEndpoint);
                server.Start();
                //Listen on master election service
                _masterElector.StartListen();

                _pingAlive = new PeerActive();
                _pingAlive.StartListen();

                Logger("{0}{1} started", VerTag, _masterElector.HostInstanceId);

                string info = String.Format("{0}{1} started", VerTag, _masterElector.HostInstanceId);

                // delay so peer nodes have chance to start listen
                PeerActiveClient client = new PeerActiveClient();
                while (!client.Ping())
                {
                    Thread.Sleep(TimeSpan.FromSeconds(QueryIntervalInSeconds));
                }
                Logger(VerTag + "all peers pinged!");

                client.Restart();
                while (!client.PingEcho())
                {
                    Thread.Sleep(TimeSpan.FromSeconds(QueryIntervalInSeconds));
                }
                Logger(VerTag + "all peers started!");

                MySQLClient sqlClient = new MySQLClient("MYSQL");
                bool MasterElected = false;

                //Added to check if a master is already elected for adding new instances as slaves.
                foreach (var ep in RoleEnvironment.Roles["HWCWorker_Worker"].Instances)
                {
                    if (sqlClient.CheckIfMaster(ep.InstanceEndpoints["MySQL"].IPEndpoint.Address, ep.InstanceEndpoints["MySQL"].IPEndpoint.Port))
                    {
                        MasterElected = true;
                        break;
                    }
                }

                //If master not already elected and started
                if (MasterElected == false)
                {
                    Logger("Elect master..");
                    //This method is called to start and ensure the election of a master
                    ensureMasterElected();
                }
                else //If master already elected, then start the new instances as slaves
                {
                    Logger("Master Already elected..");
                    _masterElector.getServerId();
                    addAsSlave();
                }

                while (!MySQLClient.IsRunning("MySQL"))
                {
                    Thread.Sleep(TimeSpan.FromSeconds(QueryIntervalInSeconds));
                }

                Logger(VerTag + "MySql server started!");

                //start the master watchdog thread to keep checking if the master is running
                startMasterWatchdogThread();
                #region added for backup
                //Start the full backup thread
                StartFullMasterBackupThread();
                //start incremental backup thread
                StartIncrementalMasterBackupThread();
                #endregion
                int retries = 0;
                while (!_recycleEvent.WaitOne(TimeSpan.Zero))
                {
                    if (!MySQLClient.IsRunning("MySQL"))
                    {
                        retries++;
                        Logger("MySQL server not responding. Retry ping ...");
                    }
                    else
                    {
                        retries = 0;
                        Logger("Health Monitor: MySQL server online");
                    }
                    if (retries >= RetryLimit)
                    {
                        Logger(VerTag + "MySQL server not responding. Recycling role...");
                        RoleEnvironment.RequestRecycle();
                    }
                    Thread.Sleep(TimeSpan.FromSeconds(double.Parse(RoleEnvironment.GetConfigurationSettingValue("RecycleThreadSleepTime"))));
                }
            }
            catch (Exception ex)
            {
                LogError("Error in start method of worker role: {0}", ex.Message);
            }


            Trace.WriteLine("Working", "Information");
            //}
            while (true)
            {
                Thread.Sleep(10000);
                Trace.WriteLine("Working", "Information");
            }
        }


        //public override bool OnStart()
        //{


        //    return base.OnStart();
        //    // RoleEnvironment.GetConfigurationSettingValue("StartupScript")
        //}

        public override bool OnStart()
        {
            bool useHWC = false;

            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;

            DiagnosticMonitor.Start("DiagnosticsConnectionString");

            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            RoleEnvironment.Changing += CSWRoleEnvironmentChanging;
            try
            {
                useHWC = Convert.ToBoolean(RoleEnvironment.GetConfigurationSettingValue("UseHWC"));

                if (useHWC == false)
                    return base.OnStart();
            }
            catch
            {
                return base.OnStart();
            }


            var approot = Environment.GetEnvironmentVariable("RoleRoot") + @"\approot";

            // Setup PHP Tuntime
            SetupPHPRuntime(approot);

            // Set MySQL host name and port number as environment variables
            RoleInstanceEndpoint instance = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["MySQL"];
            Environment.SetEnvironmentVariable("MYSQL_SERVER_NAME", instance.IPEndpoint.Address.ToString(), EnvironmentVariableTarget.Process);
            Environment.SetEnvironmentVariable("MYSQL_SERVER_PORT", instance.IPEndpoint.Port.ToString(), EnvironmentVariableTarget.Process);

            ServicePointManager.DefaultConnectionLimit = 12;

            var cfg = DiagnosticMonitor.GetDefaultInitialConfiguration();
            // HWC uses the event log to indicate what's broken.  This config setting is really handy when debugging bad config.
            cfg.WindowsEventLog.DataSources.Add("Application!*[System[Provider[@Name='HostableWebCore']]]");

            // Monitor PHP logs
            DirectoryConfiguration phpLogs = new DirectoryConfiguration();
            phpLogs.Container = RoleEnvironment.GetConfigurationSettingValue("PHPLogsContainerName");
            phpLogs.Path = approot + @"\php\logs";
            cfg.Directories.DataSources.Add(phpLogs);
            cfg.Directories.ScheduledTransferPeriod = TimeSpan.FromSeconds(30);
            cfg.Logs.ScheduledTransferPeriod = TimeSpan.FromSeconds(30);
            cfg.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;

            // diagnosticMonitor = DiagnosticMonitor.Start("DiagnosticsConnectionString", cfg);

            RoleEnvironment.Changing += RoleEnvironmentChanging;

            var parameters = new NameValueCollection();
            // "DiagnosticStore" is automatically inserted and is where the diagnostic monitor will look for these
            var diagnosticStore = RoleEnvironment.GetLocalResource("DiagnosticStore").RootPath;
            parameters["LogFilesDirectory"] = Path.Combine(diagnosticStore, "LogFiles");
            parameters["FailedReqLogFilesDirectory"] = Path.Combine(diagnosticStore, "FailedReqLogFiles");
            parameters["iisCompressionCacheDirectory"] = RoleEnvironment.GetLocalResource("iisCompressionCache").RootPath;
            parameters["approot"] = approot;
            var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["HttpIn"].IPEndpoint;
            parameters["address"] = endpoint.Address.ToString();
            parameters["port"] = endpoint.Port.ToString();
            parameters["aspNetTempDirectory"] = RoleEnvironment.GetLocalResource("aspNetTemp").RootPath;
            parameters["applicationPoolName"] = "{" + Guid.NewGuid().ToString() + "}";
            parameters["machineKeyElement"] = RoleEnvironment.GetConfigurationSettingValue("machineKeyElement");

            string configPath = RoleEnvironment.GetLocalResource("Config").RootPath;

            // substitutes in the above parameters
            HWCConfig.WriteConfigFile(
                parameters,
                Path.Combine(approot, "applicationHost.config"),
                Path.Combine(configPath, "applicationHost.config"));

            // substitutes in the above parameters
            HWCConfig.WriteConfigFile(
                parameters,
                Path.Combine(approot, "web.config"),
                Path.Combine(configPath, "web.config"));

            hwcServer = new HWCServer(Path.Combine(configPath, "applicationHost.config"), Path.Combine(configPath, "web.config"));
            hwcServer.Start();

            #region Setup CloudStorageAccount Configuration Setting Publisher

            // This code sets up a handler to update CloudStorageAccount instances when their corresponding
            // configuration settings change in the service configuration file.
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                // Provide the configSetter with the initial value
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        // The corresponding configuration setting has changed, propagate the value
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            // In this case, the change to the storage account credentials in the
                            // service configuration is significant enough that the role needs to be
                            // recycled in order to use the latest settings. (for example, the 
                            // endpoint has changed)
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });
            #endregion

            #region added for backup
            _incrementalBackuprecycleEvent = new ManualResetEvent(false);
            _fullBackuprecycleEvent = new ManualResetEvent(false);
            #endregion
            //instantiates the master election service 
            _masterElector = new MasterElectionService(ElectionServiceEndpoint);

            _masterElector.NewMaster += new EventHandler<MasterSelectionEventArgs>(_masterElector_NewMaster);

            _masterRecycleEvent = new ManualResetEvent(false);
            _recycleEvent = new ManualResetEvent(false);
            _logger = new LogClient(_masterElector.HostInstanceId);
            ThisInstance = RoleEnvironment.CurrentRoleInstance;
            RoleEnvironment.Stopping += new EventHandler<RoleEnvironmentStoppingEventArgs>(RoleEnvironment_Stopping);

            return base.OnStart();
        }

        // Setup PHP Tuntime
        private void SetupPHPRuntime(string approot)
        {
            // Create sessions and logs folders
            Directory.CreateDirectory(approot + @"\php\sessions");
            Directory.CreateDirectory(approot + @"\php\logs");

            // Edit php.ini with correct path at runtime
            var parameters = new NameValueCollection();
            parameters["approot"] = approot;
            // substitutes in the above parameters
            HWCConfig.WriteConfigFile(
                parameters,
                approot + @"\php\php.ini",
                approot + @"\php\phpNew.ini");
        }

        public override void OnStop()
        {
            diagnosticMonitor.Shutdown();
            hwcServer.Stop();
            base.OnStop();
        }

        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                e.Cancel = true;
            }
        }

        void RoleEnvironment_Stopping(object sender, RoleEnvironmentStoppingEventArgs e)
        {
            Logger("{0}workerrole shutdown happened, UD:{1}\n", VerTag, ThisInstance.UpdateDomain);

            MySQLClient sqlClient = new MySQLClient("MYSQL");
            if (_masterElector.IsMaster)
            {
                bool IsReadOnly = sqlClient.MakeMasterReadOnly();
                Thread.Sleep(TimeSpan.FromMinutes(3));
                OnFailover(RoleEnvironment.CurrentRoleInstance.Id);
            }
        }

        /// <summary>
        /// starts and ensures the election of a master among the mysql instances
        /// </summary>
        private void ensureMasterElected()
        {
            try
            {
                string msg = VerTag + "Determining master";

                Logger(msg);


                if (_masterElector.RefreshMasterEndpoint())
                {
                    msg = string.Format("{0}Elected master: {1}", VerTag, _masterElector.Master.RoleInstance.Id);
                }
                else
                {
                    msg = VerTag + "No election performed, master still alive";
                }
                Logger(msg);
            }
            catch (Exception ex)
            {
                LogError("Error in EnsureMasterElected method: {0}", ex.Message);
                Logger("Stack Trace in ensureMasterElected: {0}", ex.StackTrace);
                Logger("Inner exception in ensureMasterEected: {0}", ex.InnerException);
                Logger("Source of error in ensureMasterEected", ex.Source);
                Logger("TargetSite for error in ensureMasterEected", ex.TargetSite);
            }
        }

        /// <summary>
        /// Starts a mysql instance as master
        /// </summary>
        private void startAsMaster()
        {
            try
            {

                string msg = String.Format("{0}:{1} starting as Sql master", VerTag, _masterElector.HostServerId);
                Logger(msg);

                MySQLClient sqlClient = new MySQLClient("MYSQL");
                if (!MySQLClient.IsRunning("MySQL"))
                {
                    if (!sqlClient.Start(_masterElector.HostServerId))
                    {
                        Logger(VerTag + "Script failed to start MySQL. Recycling role...");
                        //_recycleEvent.Set();
                        RoleEnvironment.RequestRecycle();
                    }
                }

                string masterStarted = String.Format("{0}:{1} started as Sql master", VerTag, _masterElector.HostServerId);

                sqlClient.ChangeToMaster(RoleEnvironment.GetConfigurationSettingValue("MySQLUserName"),
                                        RoleEnvironment.GetConfigurationSettingValue("MySQLPassword"));
                Logger("{0}:{1} started as Sql master", VerTag, _masterElector.HostServerId);
            }
            catch (Exception ex)
            {
                LogError("Error in startAsMaster: {0}", ex.Message);
            }
        }

        /// <summary>
        /// starts a mysql instance as slave
        /// </summary>
        /// <param name="chain"></param>
        private void startAsSlave(List<string> chain)
        {
            try
            {
                string msg = string.Format("{0} starting as slave MySQL:{1}", VerTag, _masterElector.HostServerId);
                Logger(msg);

                //RoleManager.WriteToLog("Information", msg);
                MySQLClient sqlClient = new MySQLClient("MYSQL");
                if (!MySQLClient.IsRunning("MySQL"))
                {
                    if (!sqlClient.Start(_masterElector.HostServerId))
                    {
                        msg = "Script failed to start MySQL. Recycling role...";

                        Logger(VerTag + msg);
                        //_recycleEvent.Set();
                        RoleEnvironment.RequestRecycle();
                        return;
                    }
                }

                // Always the last node will be the master (1master-nslave implementation)                
                KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(chain[chain.Count - 1]);

                if (string.IsNullOrEmpty(epInfo.Key))
                {
                    msg = "failed getting master endpoint for slave at " + chain[chain.Count - 1];
                    Logger(msg);
                    return;
                }

                msg = string.Format("{0} slave's master at {1}:{2}:{3}",
                    VerTag,
                    chain[chain.Count - 1], epInfo.Key, epInfo.Value);

                Logger(msg);

                sqlClient.ChangeToSlave(epInfo.Key, epInfo.Value,
                    RoleEnvironment.GetConfigurationSettingValue("MySQLUserName"),
                    RoleEnvironment.GetConfigurationSettingValue("MySQLPassword"));

                msg = string.Format("{0} started as slave MySQL:{1}", VerTag, _masterElector.HostServerId);
                Logger(msg);
            }
            catch (Exception ex)
            {
                LogError("Error in startAsSlave: {0}", ex.Message);
            }
        }

        /// <summary>
        /// On election of new master
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _masterElector_NewMaster(object sender, MasterSelectionEventArgs e)
        {
            try
            {
                List<string> chain = e.DaisyChain;
                if (_masterElector.IsMaster)
                {
                    startAsMaster();
                }
                else
                {
                    startAsSlave(chain);
                }
            }
            catch (Exception ex)
            {
                LogError("Error in NewMasterEvent: {0}", ex.Message);
            }
        }

        /// <summary>
        /// This thread keeps checking is the master is running for every 2 minutes and if it is down
        /// will implement the failover logic to elect one of the slaves as master and make other slaves 
        /// replicate from new master
        /// </summary>
        private void startMasterWatchdogThread()
        {
            string msg = VerTag + "Determining master on failover";
            Logger("Master Watchdog thread");
            if (_masterElector.IsMaster)
            {
                //startHealthMonitorThread will do the monitoring for Master node
                return;
            }
            _masterWatchdogThread = new Thread(delegate()
            {
                int retries = 0;
                while (!_masterRecycleEvent.WaitOne(TimeSpan.Zero))
                {
                    Logger("Executing start master watchdog thread");
                    string FailedMaster = string.Empty;
                    //if validate master fails implement failover logic
                    if (!_masterElector.ValidateMaster())
                    {
                        Logger("startmasterwatchdog:ValidateMaster failed");
                        if (_masterElector.Master != null)
                        {
                            FailedMaster = _masterElector.Master.RoleInstance.Id.ToLower();
                            Logger("Failed Master: {0}, {1}", FailedMaster, instanceId);
                        }
                        retries++;
                    }
                    else
                    {
                        Logger("startmasterwatchdog:ValidateMaster success");
                        retries = 0;
                    }

                    if (retries >= RetryLimit)
                    {
                        Logger("Failed Master after retry limit over: {0}, {1}", FailedMaster, instanceId);
                        OnFailover(FailedMaster);
                        retries = 0;
                    }
                    Thread.Sleep(TimeSpan.FromMinutes(3));
                }
            });

            _masterWatchdogThread.Start();
        }

        private void OnFailover(string FailedMaster)
        {
            try
            {
                IsFailover = true;
                Logger("OnFailover-Start:IsFailover: {0}", IsFailover.ToString());
                Environment.SetEnvironmentVariable("IsFullbackUpDone", "False", EnvironmentVariableTarget.Process);
                MySQLClient sqlClient = new MySQLClient("MYSQL");
                KeyValuePair<string, RoleInstanceEndpoint>? toMaster = null;
                List<KeyValuePair<string, RoleInstanceEndpoint>> instances = new List<KeyValuePair<string, RoleInstanceEndpoint>>();
                Logger("{0}MySQL master not responding. Executing failover...", VerTag);
                KeyValuePair<string, RoleInstanceEndpoint>? newMaster = new KeyValuePair<string, RoleInstanceEndpoint>();
                bool NewMasterElected = false;
                string endpointCount = RoleEnvironment.Roles["HWCWorker_Worker"].Instances.Count.ToString();
                Logger("{0}MasterFailover. Endpoint instances count on failover: {1}", VerTag, endpointCount);

                //code executed on failover of master                        
                //Add the slave instances to a list
                foreach (var ep in RoleEnvironment.Roles["HWCWorker_Worker"].Instances)
                {
                    if (!(ep.InstanceEndpoints["MySQL"].RoleInstance.Id.ToLower().Equals(FailedMaster.ToLower())))
                    {
                        instances.Add(new KeyValuePair<string, RoleInstanceEndpoint>(ep.InstanceEndpoints["MySQL"].RoleInstance.Id, ep.InstanceEndpoints["MySQL"]));
                    }
                }

                //Order the list by instance id to get the same order accross role instances
                var list = instances.OrderBy(x => x.Key).ToList();

                //check if the update domains of all slaves are different by more than one
                //do failover only if its different
                while (!IsUpdateDomainSame(list))
                {
                    Logger("OnFailover: In while loop checking for update domain");
                    Thread.Sleep(TimeSpan.FromSeconds(20));
                }

                Logger("OnFailover: outside while loop checking for update domain");
                //Delay for peers to listen to new master
                Logger("OnFailover: Delay to check if master already elected");
                Thread.Sleep(TimeSpan.FromMinutes(1));
                foreach (KeyValuePair<string, RoleInstanceEndpoint> mysqlInstance in list)
                {
                    Logger("OnFailover: Delay few seconds check if master already elected");
                    //Delay for peers to listen to new master
                    Thread.Sleep(TimeSpan.FromSeconds(20));
                    System.Net.IPAddress Host = mysqlInstance.Value.IPEndpoint.Address;
                    int Port = mysqlInstance.Value.IPEndpoint.Port;
                    if (sqlClient.CheckIfMaster(Host, Port))
                    {
                        Logger("OnFailover: New master already elected");
                        NewMasterElected = true;
                        _masterElector._cachedMaster = mysqlInstance.Value;
                        newMaster = mysqlInstance;
                        break;
                    }
                }

                if (NewMasterElected == false)
                {
                    Logger("Promoting a slave as master");
                    //check which slave is sync with master, this slave will be promoted as master
                    foreach (KeyValuePair<string, RoleInstanceEndpoint> item in list)
                    {
                        KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(item.Key);
                        bool inSync = sqlClient.IsSlaveInSyncWithMaster(epInfo.Key, epInfo.Value);
                        if (inSync == true)
                        {
                            Logger("Slave insync with old master:OnFailover: {0}", item.Value.IPEndpoint.Address.ToString());
                            toMaster = item;
                            break;
                        }
                    }

                    //if a slave is insync with master, then promote it as slave
                    if (toMaster.Value.Key != null && toMaster.Value.Value != null)
                    {
                        KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(toMaster.Value.Key);
                        sqlClient.ChangeSlaveToMaster(epInfo.Key, epInfo.Value,
                            RoleEnvironment.GetConfigurationSettingValue("MySQLUserName"),
                            RoleEnvironment.GetConfigurationSettingValue("MySQLPassword"));
                        _masterElector._cachedMaster = toMaster.Value.Value;
                        newMaster = toMaster.Value;
                    }
                    else
                    {
                        //if none of the slaves are in sync
                        List<BinLogInfo> binLogs = new List<BinLogInfo>();
                        //get the list of binlog info for the slaves
                        foreach (KeyValuePair<string, RoleInstanceEndpoint> item in list)
                        {
                            KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(item.Key);
                            binLogs.Add(sqlClient.GetBinLogInfoForSlave(epInfo.Key, epInfo.Value, item.Key, item.Value));
                        }
                        bool newMasterElected = false;
                        //check if one of the slaves is already elected as master
                        //the bin log info for a slave already promoted as master will be null
                        foreach (BinLogInfo logInfo in binLogs)
                        {
                            if (logInfo == null)
                            {
                                newMasterElected = true;
                                break;
                            }
                        }
                        //If no new master is elected
                        if (newMasterElected == false)
                        {
                            Logger("Master being elected using bin log order by");

                            //order the bin log info by log file id and position
                            var orderedList = binLogs.OrderBy(x => x.LogId).ThenBy(x => x.Position).ToList();
                            //get the ordered list
                            List<KeyValuePair<string, RoleInstanceEndpoint>> nodes = new List<KeyValuePair<string, RoleInstanceEndpoint>>();
                            foreach (BinLogInfo info in orderedList)
                            {
                                nodes.Add(new KeyValuePair<string, RoleInstanceEndpoint>(info.HostInstanceId, info.EndPoint));
                            }
                            //Promote the slave with highest log file id and position values as master
                            KeyValuePair<string, int> ep = _masterElector.GetMySqlEndpointInfo(nodes[nodes.Count - 1].Key);
                            sqlClient.ChangeSlaveToMaster(ep.Key, ep.Value,
                                RoleEnvironment.GetConfigurationSettingValue("MySQLUserName"),
                                RoleEnvironment.GetConfigurationSettingValue("MySQLPassword"));
                            _masterElector._cachedMaster = nodes[nodes.Count - 1].Value;
                            newMaster = nodes[nodes.Count - 1];
                        }
                    }
                }

                if (newMaster.Value.Key != null && newMaster.Value.Value != null)
                {
                    //Replicate the other slaves from new master                        
                    string masterHost = newMaster.Value.Value.IPEndpoint.Address.ToString();//_masterElector._cachedMaster.IPEndPoint.Address.ToString();
                    int masterPort = newMaster.Value.Value.IPEndpoint.Port;//_masterElector._cachedMaster.IPEndPoint.Port;
                    Logger("New master elected on failover: {0}, {1}, {2}", masterHost, masterPort, instanceId);

                    foreach (KeyValuePair<string, RoleInstanceEndpoint> item in list)
                    {
                        KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(item.Key);
                        if (!(item.Value.RoleInstance.Id.ToLower().Equals(newMaster.Value.Value.RoleInstance.Id.ToLower())))//(_masterElector._cachedMaster.RoleInstance.ID.ToLower())))
                        {
                            //Make slave replicate from new master
                            sqlClient.ChangeSlavesMaster(masterHost, masterPort, epInfo.Key, epInfo.Value,
                                RoleEnvironment.GetConfigurationSettingValue("MySQLUserName"),
                                RoleEnvironment.GetConfigurationSettingValue("MySQLPassword"));
                        }
                    }
                }
                else
                {
                    Logger("No new master elected on failover: {0}", instanceId);
                }
            }
            catch (Exception ex)
            {
                IsFailover = false;
                Logger("Error OnFailover: {0}", ex.Message + ex.StackTrace);
            }
            IsFailover = false;
            Logger("OnFailover-End:IsFailover: {0}", IsFailover.ToString());
        }

        /// <summary>
        /// check if the update domains of slaves are different
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private bool IsUpdateDomainSame(List<KeyValuePair<string, RoleInstanceEndpoint>> list)
        {
            //initialize the boolean
            bool IsDifferent = false;
            try
            {
                //check only if the number of slaves is more than 1
                if (list.Count > 1)
                {
                    List<int> domainCounts = new List<int>();
                    //get the domain counts of all slaves
                    foreach (KeyValuePair<string, RoleInstanceEndpoint> mysqlInstance in list)
                    {
                        domainCounts.Add(mysqlInstance.Value.RoleInstance.UpdateDomain);
                    }
                    Logger("IsUpdateDomainSame: ListCount: {0}", domainCounts.Count.ToString());
                    //get the distinct domain count value
                    List<int> distinctList = domainCounts.Distinct().ToList();
                    Logger("IsUpdateDomainSame: DistinctListCount: {0}", distinctList.Count.ToString());
                    //if the distinct set count is more than 1 only than the update count is
                    //different for more than one slave
                    if (distinctList.Count > 1)
                    {
                        IsDifferent = true;
                    }
                }
                else
                {
                    IsDifferent = true;
                }
            }
            catch (Exception ex)
            {
                Logger("Error IsUpdateDomainSame: {0}", ex.Message + ex.StackTrace);
            }
            Logger("IsUpdateDomainSame: IsDifferent: {0}", IsDifferent.ToString());
            return IsDifferent;
        }

        /// <summary>
        /// Log message in cloud
        /// </summary>
        /// <param name="fmt"></param>
        /// <param name="args"></param>
        private void Logger(string fmt, params object[] args)
        {
            _logger.Log(fmt, args);
        }

        /// <summary>
        /// Log error in cloud.
        /// </summary>
        /// <param name="fmt"></param>
        /// <param name="args"></param>
        protected void LogError(string fmt, params object[] args)
        {
            _logger.Log(fmt, args);
        }

        /// <summary>
        /// starts a mysql instance as slave
        /// </summary>
        /// <param name="chain"></param>
        private void addAsSlave()
        {
            try
            {
                Logger("Inside addAsSlave method");
                string msg = string.Format("{0} starting as slave MySQL:{1}", VerTag, _masterElector.HostServerId);
                Logger(msg);
                MySQLClient sqlClient = new MySQLClient("MYSQL");
                if (!MySQLClient.IsRunning("MySQL"))
                {
                    if (!sqlClient.Start(_masterElector.HostServerId))
                    {
                        msg = "Script failed to start MySQL. Recycling role...";
                        Logger(VerTag + msg);
                        //_recycleEvent.Set();
                        RoleEnvironment.RequestRecycle();
                        return;
                    }
                }

                RoleInstanceEndpoint masterEP = null;
                //Added to get the master instance endpoint IP and port
                foreach (var ep in RoleEnvironment.Roles["HWCWorker_Worker"].Instances)
                {
                    if (!(ep.InstanceEndpoints["MySQL"].RoleInstance.Id.Equals(RoleEnvironment.CurrentRoleInstance.Id)))
                    {
                        if (sqlClient.CheckIfMaster(ep.InstanceEndpoints["MySQL"].IPEndpoint.Address, ep.InstanceEndpoints["MySQL"].IPEndpoint.Port))
                        {
                            masterEP = ep.InstanceEndpoints["MySQL"];
                            _masterElector._cachedMaster = ep.InstanceEndpoints["MySQL"];
                            break;
                        }
                    }
                }

                // Get the master endpoint info
                KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(masterEP.RoleInstance.Id);

                Logger(msg);
                sqlClient.ChangeToSlave(epInfo.Key, epInfo.Value,
                    RoleEnvironment.GetConfigurationSettingValue("MySQLUserName"),
                    RoleEnvironment.GetConfigurationSettingValue("MySQLPassword"));
                msg = string.Format("{0} started as slave MySQL:{1}", VerTag, _masterElector.HostServerId);
                Logger(msg);
            }
            catch (Exception ex)
            {
                LogError("Error in startAsSlave: {0}", ex.Message);
            }
        }

        #region Added for backup
        #region Full backup

        /// <summary>
        /// Thread to execute the full backup of mysql master data
        /// </summary>
        private void StartFullMasterBackupThread()
        {
            Environment.SetEnvironmentVariable("IsFullbackUpDone", "False", EnvironmentVariableTarget.Process);
            Logger("IsFullBackupDone set to false");
            Logger("Inside Backup thread: {0}", DateTime.Now.ToString());

            _setFullBackupThread = new Thread(delegate()
            {
                while (!_fullBackuprecycleEvent.WaitOne(TimeSpan.Zero))
                {
                    //check if the backup is enabled in configuration
                    string EnableBackup = RoleEnvironment.GetConfigurationSettingValue("EnableBackup");
                    Logger("BackupEnabled: {0}", EnableBackup);
                    //do backup only if backup is enabled
                    if (EnableBackup == "True")
                    {
                        Logger("FullBackupThread:IsFailover: {0}", IsFailover.ToString());
                        //check if failover is happening, if yes do not do backup
                        if (IsFailover == false)
                        {
                            string IsFullBackupDone = Environment.GetEnvironmentVariable("IsFullbackUpDone", EnvironmentVariableTarget.Process);
                            Logger("FullBackup:IsFullBackupDone: {0}", IsFullBackupDone);
                            DateTime dateNow = DateTime.Now.Date;
                            Logger("FullBackup:CurrentDate: {0}", dateNow);
                            //reset the IsFullBackupDone flag everyday
                            if (FullBackupDate.HasValue)
                            {
                                Logger("FullBackup:LastFullBackupDate: {0}", FullBackupDate.Value.ToString());
                                if (FullBackupDate.Value.CompareTo(dateNow) == -1 && IsFullBackupDone == "True")
                                {
                                    Logger("FullBackup:Setting flag to false on comparing last full backup date with today");
                                    Environment.SetEnvironmentVariable("IsFullbackUpDone", "False", EnvironmentVariableTarget.Process);
                                }
                            }
                            else
                            {
                                Logger("FullBackup:Setting flag to false");
                                Environment.SetEnvironmentVariable("IsFullbackUpDone", "False", EnvironmentVariableTarget.Process);
                            }
                            Logger("FullBackupThread:IsIncrementalBackupRunning: {0}", IsIncrementalBackupRunning.ToString());
                            //check if incremental backup is running, if yes do not do full backup at that time
                            if (IsIncrementalBackupRunning == false)
                            {
                                //check if the hour is reached for full backup                        
                                Logger("FullBackupThread:IsFullBackupDone: {0}", IsFullBackupDone);
                                Logger("Checking backup time: {0}", DateTime.Now.ToString());
                                //if the time is past the configured time and full backup has not been done start it immediately
                                //else wait for the configured time
                                if (IsItFullBackupTime())
                                {
                                    Logger("Full backup time matched");
                                    DoFullBackup();
                                }
                                else if (IsCurrentTimeGrtThanFullBackupTime() && IsFullBackupDone.Equals("False"))
                                {
                                    Logger("Time past full back time and full backup flag is false");
                                    DoFullBackup();
                                }
                            }
                        }
                    }
                    Thread.Sleep(TimeSpan.FromSeconds(60));
                }
            });

            _setFullBackupThread.Start();
        }

        /// <summary>
        /// Do full backup of mysql
        /// </summary>
        private void DoFullBackup()
        {
            try
            {
                Logger("Its backup time: {0}", DateTime.Now.ToString());

                MySQLClient sqlClient = new MySQLClient("MYSQL");

                RoleInstanceEndpoint ep = ThisInstance.InstanceEndpoints["MySQL"];
                //do the backup only on master
                if (sqlClient.CheckIfMaster(ep.IPEndpoint.Address, ep.IPEndpoint.Port))
                {
                    IsFullBackupRunning = true;
                    //Take a full backup of mysql master database
                    Logger("got the mysql master: {0}", instanceId);

                    string baseDir = RoleEnvironment.GetLocalResource("MySQL").RootPath;
                    string dataDir = RoleEnvironment.GetLocalResource("MySQLDatastore").RootPath.Replace('\\', '/');

                    string command = Path.Combine(baseDir, @"bin\mysqldump.exe");

                    if (!File.Exists(command))
                    {
                        SetupAzureMySql(baseDir);
                        SetupAzureMySql(dataDir);
                    }

                    try
                    {
                        string backupFileName = dataDir + "MasterBackup_" + DateTime.Now.ToString("ddMMMyyyy") + ".sql";
                        string backupErrorLog = dataDir + "MasterBackupError_" + DateTime.Now.ToString("ddMMMyyyy") + ".log";
                        KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(ThisInstance.Id);
                        string backupCommand = " -u root -h " + epInfo.Key + " -P " + epInfo.Value.ToString() + " -q -R --all-databases > " + backupFileName;
                        Logger("Full Backup command: {0}, {1}", command, backupCommand);
                        string mysqlCommand = "" + command + "";

                        string sqlCommand = "\"" + command + "\"" + backupCommand;
                        string output = RunMySqlCommand(sqlCommand);
                        Logger("FullBackup: mysqldump completed");

                        #region Write the content into a blob storage
                        //Code to Get Blob container 

                        // Container which has the MySQLBackup logs and incremental logs
                        string containerName = RoleEnvironment.GetConfigurationSettingValue("ContainerName");
                        //Changing it to lower case as upper case letters are not allowed in container names
                        //Refer to http://msdn.microsoft.com/en-us/library/dd135715.aspx for restrictions on blob container names
                        containerName = containerName.ToLower();
                        string serverIP = ep.IPEndpoint.Address.ToString().Replace('.', '-');
                        containerName = containerName + "-" + serverIP;
                        var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
                        CloudBlobClient blobStorage = storageAccount.CreateCloudBlobClient();
                        CloudBlobContainer newContainer = blobStorage.GetContainerReference(containerName);
                        newContainer.CreateIfNotExist();
                        var permissions = newContainer.GetPermissions();

                        permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                        permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
                        newContainer.SetPermissions(permissions);


                        //Creating FileStream and other Blob properties to create blob for each file
                        FileStream fs;

                        byte[] data;
                        NameValueCollection metadata;
                        // Blob

                        Logger("Write full backup to Blob process started.");

                        CloudBlockBlob content = null;
                        //Loop throught the entire data directory and log only the files which are not in Blob Container
                        DirectoryInfo di = new DirectoryInfo(dataDir);
                        foreach (FileInfo fi in di.GetFiles())
                        {
                            content = newContainer.GetBlockBlobReference(fi.Name);

                            //Check if the log file already exists in Blob. If it is there don't write it
                            //Excluding the current file
                            //Writing only the log files which starts with mysql
                            if ((content != null) && (fi.Name.EndsWith("MasterBackup_" + DateTime.Now.ToString("ddMMMyyyy") + ".sql")))
                            {
                                bool Exists = content.DeleteIfExists();
                                //Excluding the current log file we are writing all the log files.
                                fs = fi.OpenRead();
                                data = new byte[fs.Length];
                                fs.Read(data, 0, data.Length);
                                metadata = new NameValueCollection();
                                metadata["Id"] = Guid.NewGuid().ToString();
                                metadata["Filename"] = fi.Name;
                                metadata["Name"] = fi.Name;
                                metadata["Description"] = fi.Name;
                                string filePath = Path.Combine(dataDir, fi.Name);

                                content.UploadFile(filePath);

                                Logger("Write full backup to Blob process ended.");
                                Environment.SetEnvironmentVariable("IsFullbackUpDone", "True", EnvironmentVariableTarget.Process);
                                string IsFullBackupDone = Environment.GetEnvironmentVariable("IsFullbackUpDone", EnvironmentVariableTarget.Process);
                                Logger("DoFullBackup:Full backup done flag: {0}", IsFullBackupDone);
                                FullBackupDate = DateTime.Now.Date;
                            }
                            content = null;
                        }

                        #endregion

                    }
                    catch (Exception ex)
                    {
                        IsFullBackupRunning = false;
                        Environment.SetEnvironmentVariable("IsFullbackUpDone", "False", EnvironmentVariableTarget.Process);
                        Logger("Exception in full backup thread: {0}, {1}", ex.Message, ex.StackTrace);
                    }
                    Logger("Backup process Completed on: {0}", DateTime.Now.ToString());
                    IsFullBackupRunning = false;
                }
            }
            catch (Exception ex)
            {
                IsFullBackupRunning = false;
                Environment.SetEnvironmentVariable("IsFullbackUpDone", "False", EnvironmentVariableTarget.Process);
                Logger("Exception in Do Full backup thread: {0}", ex.Message + ex.StackTrace);
            }

        }

        /// <summary>
        /// check if the current time is same as 
        /// configured full backup time
        /// </summary>
        /// <returns></returns>
        private bool IsItFullBackupTime()
        {
            if (string.Equals(DateTime.Now.ToString("HH:mm"), RoleEnvironment.GetConfigurationSettingValue("FullBackupHour")))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// check if the current time is greater than 
        /// configured full backup time
        /// </summary>
        /// <returns></returns>
        private bool IsCurrentTimeGrtThanFullBackupTime()
        {
            TimeSpan fullBackupTime = DateTime.Parse(RoleEnvironment.GetConfigurationSettingValue("FullBackupHour")).TimeOfDay;
            if (DateTime.Now.TimeOfDay.CompareTo(fullBackupTime) == 1)
            {
                return true;
            }
            return false;
        }


        /// <summary>
        /// Copies mysql binaries to root folder
        /// </summary>
        /// <param name="rootDir"></param>
        /// <returns></returns>
        private bool SetupAzureMySql(string rootDir)
        {
            if (!Directory.Exists("mysql"))
            {
                return false;
            }
            CopyDir("mysql", rootDir);
            return true;
        }

        /// <summary>
        /// Copies the files and folders recursively from source to destination
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <returns></returns>
        private static bool CopyDir(string src, string dst)
        {
            try
            {
                if (!Directory.Exists(dst))
                {
                    Directory.CreateDirectory(dst);
                }
                string[] subDirs = Directory.GetDirectories(src);
                foreach (string dir in subDirs)
                {
                    int pos = dir.LastIndexOf('\\');
                    string target = Path.Combine(dst, dir.Substring(pos + 1));
                    CopyDir(dir, target);
                }
                string[] files = Directory.GetFiles(src);
                foreach (string file in files)
                {
                    string targetFile = Path.Combine(dst, Path.GetFileName(file));
                    File.Copy(file, targetFile);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }
        #endregion

        #region Incremental backup
        /// <summary>
        /// Thread to execute the incremental backup for mysql
        /// </summary>
        private void StartIncrementalMasterBackupThread()
        {
            Logger("Inside Backup thread: {0}", DateTime.Now.ToString());

            _setIncrementalBackupThread = new Thread(delegate()
            {
                while (!_incrementalBackuprecycleEvent.WaitOne(TimeSpan.Zero))
                {
                    //check if the backup is enabled in configuration
                    string EnableBackup = RoleEnvironment.GetConfigurationSettingValue("EnableBackup");
                    Logger("BackupEnabled: {0}", EnableBackup);
                    //do backup only if backup is enabled
                    if (EnableBackup == "True")
                    {
                        //check if failover is happening, if yes do not do backup
                        Logger("IncrementalBackupThread:IsFailover: {0}", IsFailover.ToString());
                        if (IsFailover == false)
                        {
                            //check if full backup is happening, if yes do not do incremental backup
                            if (IsFullBackupRunning == false)
                            {
                                try
                                {
                                    Logger("Incremental backup time matched");
                                    //check if the hour is reached for full backup
                                    Logger("Checking backup time: {0}", DateTime.Now.ToString());

                                    MySQLClient sqlClient = new MySQLClient("MYSQL");

                                    RoleInstanceEndpoint ep = ThisInstance.InstanceEndpoints["MySQL"];
                                    //do the backup only on master
                                    if (sqlClient.CheckIfMaster(ep.IPEndpoint.Address, ep.IPEndpoint.Port))
                                    {
                                        IsIncrementalBackupRunning = true;
                                        Logger("Incremental backup: In Master: {0}", instanceId);
                                        //Take a full backup of mysql master database
                                        string dataDir = RoleEnvironment.GetLocalResource("MySQLDatastore").RootPath.Replace('\\', '/');
                                        string masterLogFile = string.Empty;
                                        KeyValuePair<string, int> epInfo = _masterElector.GetMySqlEndpointInfo(ThisInstance.Id);
                                        Logger("Before flush log");
                                        masterLogFile = sqlClient.FlushLog(epInfo.Key, epInfo.Value);
                                        Logger("After flush log: {0}", masterLogFile);
                                        //Code to Get Blob container 

                                        // Container which has the MySQLBackup logs and incremental logs                                
                                        string containerName = RoleEnvironment.GetConfigurationSettingValue("ContainerName");
                                        string serverIP = ep.IPEndpoint.Address.ToString().Replace('.', '-');
                                        containerName = containerName + "-" + serverIP;
                                        var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
                                        CloudBlobClient blobStorage = storageAccount.CreateCloudBlobClient();
                                        CloudBlobContainer newContainer = blobStorage.GetContainerReference(containerName);
                                        newContainer.CreateIfNotExist();
                                        var permissions = newContainer.GetPermissions();

                                        permissions.PublicAccess = BlobContainerPublicAccessType.Container;
                                        permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
                                        newContainer.SetPermissions(permissions);
                                        //Creating FileStream and other Blob properties to create blob for each file
                                        FileStream fs;

                                        byte[] data;
                                        NameValueCollection metadata;

                                        CloudBlockBlob content = null;

                                        //Loop throught the entire data directory and log only the files which are not in Blob Container
                                        DirectoryInfo di = new DirectoryInfo(dataDir);
                                        foreach (FileInfo fi in di.GetFiles())
                                        {
                                            //Check if the log file already exists in Blob. If it is there don't write it
                                            //Excluding the current file
                                            //Writing only the log files which starts with mysql
                                            content = newContainer.GetBlockBlobReference(fi.Name);

                                            if ((content != null) && (fi.Name != masterLogFile) && (fi.Name.StartsWith("mysql")) && (fi.Name != "mysql-bin.index"))
                                            {
                                                bool Exists = content.DeleteIfExists();
                                                //Excluding the current log file we are writing all the log files.
                                                fs = fi.OpenRead();
                                                data = new byte[fs.Length];
                                                fs.Read(data, 0, data.Length);
                                                metadata = new NameValueCollection();
                                                metadata["Id"] = Guid.NewGuid().ToString();
                                                metadata["Filename"] = fi.Name;
                                                metadata["Name"] = fi.Name;
                                                metadata["Description"] = fi.Name;
                                                string filePath = Path.Combine(dataDir, fi.Name);
                                                content.UploadFile(filePath);
                                            }
                                            content = null;
                                        }
                                    }
                                    IsIncrementalBackupRunning = false;
                                }
                                catch (Exception ex)
                                {
                                    IsIncrementalBackupRunning = false;
                                    Logger("Exception in Incremental backup thread: {0}", ex.Message + ex.StackTrace);
                                }
                            }
                        }
                    }
                    Thread.Sleep(TimeSpan.FromMinutes(double.Parse(RoleEnvironment.GetConfigurationSettingValue("IncrementalBackupDuration"))));
                }
            });

            _setIncrementalBackupThread.Start();
        }

        /// <summary>
        /// Checks if current time is equal to time
        /// set for incremental backup in environment variable
        /// </summary>
        /// <returns></returns>
        private bool IsItIncrementalBackupTime()
        {
            //Check if the environment variable set is equal to the current system time.
            if (int.Parse(DateTime.Now.ToString("HH:mm").Split(':')[0]) == int.Parse(RoleEnvironment.GetConfigurationSettingValue("FullBackupHour")))
            {
                return true;
            }
            return false;

        }

        /// <summary>
        /// function to run DOS command.
        /// </summary>
        /// <param name="inputLine">input from TCP client.</param>
        /// <returns></returns>
        private string RunMySqlCommand(string inputLine)
        {
            string currentDir = string.Empty;
            string driveName = string.Empty;
            string command = string.Empty;
            string fileExtension = string.Empty;
            string returnDetails = string.Empty;

            Process newProc = new Process();

            try
            {
                newProc.StartInfo.UseShellExecute = false;
                newProc.StartInfo.RedirectStandardOutput = true;
                newProc.StartInfo.CreateNoWindow = true;
                newProc.StartInfo.RedirectStandardInput = true;
                newProc.StartInfo.RedirectStandardOutput = true;
                newProc.StartInfo.RedirectStandardError = true;
                newProc.StartInfo.FileName = "cmd.exe";

                newProc.EnableRaisingEvents = false;
                newProc.Start();

                StreamWriter sIn = newProc.StandardInput;
                StreamReader sOut = newProc.StandardOutput;
                StreamReader sErr = newProc.StandardError;

                sIn.AutoFlush = true;
                if (!string.IsNullOrEmpty(inputLine.Trim()))
                {
                    command = inputLine;
                    sIn.Write(command + System.Environment.NewLine);
                }

                sIn.Close();

                returnDetails = sOut.ReadToEnd();
                if (!string.IsNullOrEmpty(inputLine.Trim()))
                {
                    //get output of last command
                    int outStartIndex = returnDetails.IndexOf(inputLine) + inputLine.Length;
                    returnDetails = returnDetails.Substring(outStartIndex).TrimStart();
                }

                string errDetails = sErr.ReadToEnd();
                if (!string.IsNullOrEmpty(errDetails.Trim()))
                {
                    returnDetails = errDetails + System.Environment.NewLine + returnDetails;
                }

            }
            catch (Exception ex)
            {
                Logger("RunCommand Error:{0}", ex.Message + ex.StackTrace);
                returnDetails = "Error: " + ex.Message + System.Environment.NewLine + returnDetails;
            }
            finally
            {
                newProc.Close();
            }

            return returnDetails;
        }

        #endregion
        #endregion


        #region Added By Sudhir
        private void Execute(object obj)
        {
            string result = ExecutePHP();

            //Write the result
            Trace.WriteLine(result);
        }

        /// <summary>
        /// Execute the PHP Startup Script
        /// </summary>
        /// <returns>Result</returns>  
        private string ExecutePHP()
        {
            try
            {
                Process p = new Process();

                // Get RoleRoot from Environment
                string roleRoot = Environment.GetEnvironmentVariable("RoleRoot");

                //ProcessStartInfo
                ProcessStartInfo info = new ProcessStartInfo(@"C:\Program Files (x86)\PHP\php.exe",
                                        RoleEnvironment.GetConfigurationSettingValue("StartupScript"));

                info.RedirectStandardOutput = true;
                info.RedirectStandardError = true;
                info.UseShellExecute = false;
                info.CreateNoWindow = true;

                p.StartInfo = info;

                //Events for output and error
                p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
                p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);

                //Start the process
                bool isStarted = p.Start();

                p.BeginOutputReadLine();
                p.BeginErrorReadLine();

                p.WaitForExit();
                if (p.ExitCode != 0)
                {
                    throw new Exception("PHP has failed");
                }

                //Get output in String Builder
                StringBuilder sb = output.GetStringBuilder();
                string res = sb.ToString();

                //Clear the output stream
                sb.Remove(0, sb.Length);

                //Return the result
                return res;
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, "Error");
                return null;
            }
        }

        /// <summary>
        /// Error Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            //Write Error
            if (e.Data != null)
                error.WriteLine("Error: " + e.Data);
        }

        /// <summary>
        /// Output Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            //Write Output
            if (e.Data != null)
                output.WriteLine(e.Data);
        }

        private void CSWRoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // If a configuration setting is changing
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }
        #endregion
    }
}